 
/* 
 * Copyright (C) Ignacio Lucas
 */
 
/*
 *  common_objects_pool, hecho por Ignacio Lucas
 *
 *  Vector de objetos object_pool con los objetos más utilizados en la aplicación.
 *  Los objetos más comunes son: sockets, job, stack (espacio de memoria donde ejecuta la corrutina), objeto http_request,
 *  objeto http-response, objeto incremental_buffer, objeto socket, objeto hashmap y objeto hashmap_entry.
 *  Ignacio Lucas <ignacio.lucas@gmail.com>
 *
 */
#include "common_objects_pool.h"
#include "socket.h"
#include "worker.h"
#include "utils/hashmap.h"
#include "user_pools.h"

typedef struct s_common_objects_pool_item
{
	object_pool op;
	// worker provee sincronismo individualizado para los MAX_POOLS disponibles.
	// en este offset me guardo a cual de dichos MAX_POOLS le corresponde.
	// en caso de no tener acceso exclusivo, se guardara el valor -1.
	int exclusive_offset;

} common_objects_pool_item;


typedef struct s_common_objects_pool
{
	common_objects_pool_item p[MAX_POOLS];
	int pool_count;
	hashmap_t user_pools_map;
	
} common_objects_pool;

static common_objects_pool common_pool;

int common_objects_pool_get_pool_count()
{
	return common_pool.pool_count;
}

// inicialización del vector de object_pool
int common_objects_pool_init(int pool_count, object_pool_conf *conf)
{
	int ret=0, i=0, j=0, next_exclusive=0;
	common_objects_pool_item *opitem = NULL;
	object_pool_conf *opconf = NULL;

	common_pool.pool_count=0;
	common_pool.user_pools_map = NULL;
	if (pool_count > MAX_POOLS)
	{
		return 1;
	}
	common_pool.pool_count=pool_count;

	for (i=0; i<pool_count; i++)
	{
		opitem = &(common_pool.p[i]);
		opconf = &(conf[i]);
		if (opconf->exclusive == 1)
		{
			opitem->exclusive_offset=next_exclusive++;
		}
		else
		{
			opitem->exclusive_offset=-1;
		}

		opconf->id=i;
		// Inicializa todos los pools.
		ret=object_pool_init(&(opitem->op), opconf);
		if (ret != 0)
		{
			for (j=0; j<i;j++)
			{
				object_pool_destroy(&(common_pool.p[j].op));
			}
			common_pool.pool_count=0;
			return 1;
		}
	}

	/** Hecho esto, cargamos la interfaz de user_pool. **/
	if (pool_count > BASE_USER_POOLS)
	{
		common_pool.user_pools_map = hashmap_create(pool_count - BASE_USER_POOLS);
		char user_pool_id[4];

		for (i=BASE_USER_POOLS,j=0; i<pool_count;i++,j++)
		{
			opconf = &(conf[i]);
			sprintf(user_pool_id,"%d",j);
			hashmap_put(common_pool.user_pools_map,opconf->name,user_pool_id);
		}
		user_pools_init(common_pool.user_pools_map);
	}

	return 0;
}

int common_objects_pool_put(int pool_offset, void *p)
{
	common_objects_pool_item *item = (&(common_pool.p[pool_offset]));
	if (item->exclusive_offset == -1)
	{
		return object_pool_put_or_free(&(item->op), p);
	}
	else
	{
		return worker_object_pool_put_exclusive(item->exclusive_offset, p, &(item->op));
	}
}

void* common_objects_pool_get(int pool_offset)
{
	common_objects_pool_item *item = (&(common_pool.p[pool_offset]));
	if (item->exclusive_offset == -1)
	{
		return object_pool_pick_or_alloc(&(item->op));
	}
	else
	{
		return worker_object_pool_get_exclusive(item->exclusive_offset, &(item->op));
	}
	return NULL;
}

int common_objects_pool_destroy()
{
	int i=0;
	for (i=0; i<common_pool.pool_count; i++)
	{
		object_pool_destroy(&(common_pool.p[i].op));
	}
	if (common_pool.user_pools_map != NULL)
	{
		hashmap_delete(common_pool.user_pools_map);
	}
	return 0;
}

